package service;

import javafx.util.Pair;
import util.ObjectUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class ServiceContainer {
    private final Pair<String,String>[] basePackages;
    /**
     * 通过url + 请求方式定位某个方法
     */
    private static final Map<Pair<String, String>, Method> URL_AND_TYPE_METHOD = new ConcurrentHashMap<>();

    /**
     * 通过方法定位class
     */
    private static final Map<Method, Object> METHOD_CLASS = new ConcurrentHashMap<>();

    @SafeVarargs
    public ServiceContainer(Pair<String,String>... basePackages) {
        if (basePackages.length==0) {
            throw new RuntimeException("包路径为空，无法解析！");
        }
        this.basePackages = basePackages;
    }

    public void start() {
        // 扫描包路径下的所有类
        Set<Class<?>> allClass = (Set<Class<?>>) Arrays.stream(basePackages)
                .map(ClassUtils::scanClass)
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());

        // 自定义接口路由
        for (Class<?> aClass : allClass) {
            Method[] declaredMethods = aClass.getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                if (declaredMethod.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping  requestMapping = declaredMethod.getAnnotation(RequestMapping.class);
                    String url = requestMapping.path();
                    String requestType = requestMapping.method();
                    if (ObjectUtil.anyNull(url, requestType)) {
                        System.out.printf("容器接口解析异常，class:%s，method：%s\n", aClass.getName(), declaredMethod.getName());
                    }
                    System.out.printf("装载http接口，url：%s，requestType：%s，class: %s，method：%s\n", url, requestType, aClass.getName(), declaredMethod.getName());
                    Pair<String, String> pair = new Pair<>(url, requestType);
                    URL_AND_TYPE_METHOD.put(pair, declaredMethod);
                    try {
                        METHOD_CLASS.put(declaredMethod, aClass.getDeclaredConstructor().newInstance());
                    } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                             NoSuchMethodException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    public static Method getTargetMethod(String url, String requestType) {
        System.out.println(url);
        Pair pair = new Pair(url, requestType);
        return URL_AND_TYPE_METHOD.get(pair);
    }

    public static Object getTargetInstanceByMethod(Method method) {
        return METHOD_CLASS.get(method);
    }

}
